/*
 * Created by Jaren at 2021/10/29 7:57
 */
import 'dart:typed_data';

import 'package:inmotion_protocol/common/compact.dart';
import 'package:inmotion_protocol/common/exceptions.dart';
import 'package:inmotion_protocol/common/product_version.dart';
import 'package:inmotion_protocol/common/vehicle_info.dart';
import 'package:inmotion_protocol/lorin/constant.dart';
import 'package:inmotion_protocol/lorin/lorin_message.dart';
import 'package:inmotion_protocol/lorin/protocol.dart';
import 'package:inmotion_protocol/lorin/util.dart';
import 'package:inmotion_protocol/util/byte_util.dart';
import 'package:inmotion_protocol/util/device.dart';

/// Lorin协议特殊组Message Factory
abstract class SpecialMessageFactory<T extends CmdCompact> {
  ProductProperty productProperty;

  SpecialMessageFactory(this.productProperty);

  T? compact;

  void initCompact(int apiVersion, VersionWrapper version);

  /// 特殊组，不指定来源设备和目标设备
  /*
  LorinMessage genSpecialOne2OneMsg(Uint8ClampedList cmd, [Uint8ClampedList? para, Uint8ClampedList? tab, int checkType = Constant.checkTypeCRC32, bool encrypt = false]) {
    LorinSpecialMessageData msgData = LorinSpecialMessageData(null, null, cmd, para);

    int format = Util.calFormat(tab == null ? Constant.noTab : Constant.hasTab, checkType, encrypt ? Constant.hasEncrypt : Constant.noEncrypt, Constant.dataTypeSpecialOne2One);
    int length = msgData.dataLength();
    return LorinMessage(LorinMessage.HEAD, ByteUtil.toUint8(format), null, tab, ByteUtil.toUint8(length), msgData, null);
  }
  */

  // 读：一对一
  LorinMessage genSpecialOne2OneReadMsg(
    int cmd, [
    Uint8ClampedList? para,
    Uint8ClampedList? tab,
    bool encrypt = false,
    int? source,
    int? target,
  ]) {
    return genSpecialMany2ManyMsg(source, target, Util.genCmd(cmd, true), para,
        tab, Constant.checkTypeParity, encrypt);
  }

  // 写：一对一
  LorinMessage genSpecialOne2OneWriteMsg(
    int cmd, [
    Uint8ClampedList? para,
    Uint8ClampedList? tab,
    bool encrypt = false,
    int? source,
    int? target,
  ]) {
    return genSpecialMany2ManyMsg(source, target, Util.genCmd(cmd, false), para,
        tab, Constant.checkTypeParity, encrypt);
  }

  // 读：多对多
  LorinMessage genSpecialMany2ManyReadMsg(
    int? source,
    int? target,
    int cmd, [
    Uint8ClampedList? para,
    Uint8ClampedList? tab,
    int checkType = Constant.checkTypeParity,
    bool encrypt = false,
  ]) {
    return genSpecialMany2ManyMsg(
        source, target, Util.genCmd(cmd, true), para, tab, checkType, encrypt);
  }

  // 写：多对多
  LorinMessage genSpecialMany2ManyWriteMsg(
    int? source,
    int? target,
    int cmd, [
    Uint8ClampedList? para,
    Uint8ClampedList? tab,
    int checkType = Constant.checkTypeParity,
    bool encrypt = false,
  ]) {
    return genSpecialMany2ManyMsg(
        source, target, Util.genCmd(cmd, false), para, tab, checkType, encrypt);
  }

  // 多对多
  LorinMessage genSpecialMany2ManyMsg(
    int? source,
    int? target,
    Uint8ClampedList cmd, [
    Uint8ClampedList? para,
    Uint8ClampedList? tab,
    int checkType = Constant.checkTypeParity,
    bool encrypt = false,
  ]) {
    var newSource = source ??=
        ProtocolGlobal.isBleSend ? Constant.sourceApp : Constant.sourceCloudBox;
    var newTarget = target ??=
        DeviceUtils.getHmicDevice(productProperty.model) == 0
            ? DeviceUtils.getBtDevice(productProperty.model)
            : DeviceUtils.getHmicDevice(productProperty.model);
    LorinSpecialMessageData msgData = LorinSpecialMessageData(
        ByteUtil.toUint8(newSource), ByteUtil.toUint8(newTarget), cmd, para);
    int format = Util.calFormat(
        tab == null ? Constant.noTab : Constant.hasTab,
        checkType,
        encrypt ? Constant.hasEncrypt : Constant.noEncrypt,
        Constant.dataTypeSpecialMany2Many);
    int length = msgData.dataLength();
    return LorinMessage(LorinMessage.HEAD, ByteUtil.toUint8(format), null, tab,
        ByteUtil.toUint8(length), msgData, null);
  }

  /// 实时数据
  LorinMessage genGetRealTimeDataMsg([Uint8ClampedList? para]) {
    return genSpecialOne2OneReadMsg(compact!.realTimeDataCmd(), para);
  }

  /// 实时状态
  LorinMessage genGetRealTimeStateMsg([Uint8ClampedList? para]) {
    return genSpecialOne2OneReadMsg(compact!.realTimeStateCmd(), para);
  }

  /// 实时警告和故障
  LorinMessage genGetRealTimeErrorMsg([Uint8ClampedList? para]) {
    return genSpecialOne2OneReadMsg(compact!.realTimeErrorCmd(), para);
  }

  /// 综合实时信息，包含实时数据、实时状态和实时警告和故障
  LorinMessage genGetAllRealTimeInfoMsg([Uint8ClampedList? para]) {
    return genSpecialOne2OneReadMsg(compact!.allRealTimeInfoCmd(), para);
  }

  /// 获取设备信息（单条指令）
  LorinMessage genGetDeviceInfoMsg([Uint8ClampedList? para]) {
    return genSpecialOne2OneReadMsg(6, para);
  }

  /// 获取设备实时信息（单条指令）
  LorinMessage genGetDeviceRealTimeInfoMsg([Uint8ClampedList? para]) {
    return genSpecialOne2OneReadMsg(compact!.deviceRealTimeInfoCmd(), para);
  }

  /// 历史统计数据
  LorinMessage genGetHistoryStatisticsMsg([Uint8ClampedList? para]) {
    return genSpecialOne2OneReadMsg(compact!.historyStatisticsCmd(), para);
  }

  /// 总计统计数据
  LorinMessage genGetTotalStatisticsMsg([Uint8ClampedList? para]) {
    return genSpecialOne2OneReadMsg(compact!.totalHistoryStatisticsCmd(), para);
  }

  /// 设备设置
  LorinMessage genGetSettingsMsg([Uint8ClampedList? para]) {
    return genSpecialOne2OneReadMsg(compact!.settingsCmd(), para);
  }

  LorinMessage genStartUpgradingFirmwareMsg(Uint8ClampedList? para) {
    return genSpecialOne2OneWriteMsg(compact!.startUpgradingFirmware(), para,
        null, false, null, Constant.deviceScreen);
  }

  LorinMessage genStartTransferFirmwareMsg(Uint8ClampedList? para) {
    return genSpecialOne2OneWriteMsg(compact!.startTransferFirmware(), para,
        null, false, null, Constant.deviceScreen);
  }

  /// 开关前照明灯
  LorinMessage genHeadlightOnOffMsg(
      {bool? on, bool? lowBeamOn, bool? highBeamOn, int? source, int? target}) {
    if (on != null)
      return genSpecialOne2OneWriteMsg(
          compact!.headlightOnOffCmd(), ByteUtil.bool2Bytes(on));
    if (highBeamOn == null || lowBeamOn == null) {
      throw InvalidParamException(
          'Both param [highBeamOn] and [lowBeamOn] could not be null when [on] is null.');
    }
    return genSpecialOne2OneWriteMsg(
        compact!.headlightOnOffCmd(),
        Uint8ClampedList.fromList([
          ByteUtil.bool2Byte(lowBeamOn).value,
          ByteUtil.bool2Byte(highBeamOn).value
        ]));
  }

  /// 锁车/解锁
  LorinMessage genLockMsg(bool lock) {
    return genSpecialOne2OneWriteMsg(
        compact!.lockCmd(), ByteUtil.bool2Bytes(lock));
  }

  /// 设置骑行模式
  LorinMessage genSetRidingModeMsg(int mode) {
    return genSpecialOne2OneWriteMsg(
        compact!.ridingModeCmd(), ByteUtil.num2BytesLe(mode, 1));
  }

  /// 设置限速值
  LorinMessage genSetSpeedLimitMsg(int speedLimit, [int? speedLimit2]) {
    return genSpecialOne2OneWriteMsg(
        compact!.speedLimitCmd(), ByteUtil.num2BytesLe(speedLimit, 2));
  }

  /// 设置氛围灯模式(开关)
  LorinMessage genSetLightEffectModeMsg(int mode,
      [Uint8ClampedList? param, int? source, int? target]) {
    throw NotSupportException("");
  }

  /// 设置安全限速开关
  LorinMessage genSafeSpeedLimitOnOffMsg(bool onOff) {
    return genSpecialOne2OneWriteMsg(
        compact!.safeSpeedLimitCmd(), ByteUtil.bool2Bytes(onOff));
  }
}

class UnknownSpecialMsgFactory extends SpecialMessageFactory {
  static final instance = UnknownSpecialMsgFactory(ProductProperty.instance);

  UnknownSpecialMsgFactory(ProductProperty productProperty)
      : super(productProperty);

  @override
  void initCompact(int apiVersion, VersionWrapper version) {
    throw UnimplementedError("Don't use this special message factory!");
  }
}
